﻿using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using YFurion.Extensions;

namespace YFurion.Application.EFCore.Extensions
{
    public static class EFCoreQueryableExtensions
    {
        public static async Task<PagedResultDto<T>> ToPagedResultAsync<T>(this IQueryable<T> query, PagedAndSortedResultRequestDto input, CancellationToken cancellationToken = default)
        {
            int count = await query.CountAsync(cancellationToken);
            query = query.PageBy(input)
                .OrderByIf(!input.Sorting.IsNullOrWhiteSpace(), input.Sorting);
            List<T> entityDtos = await query.ToListAsync(cancellationToken);
            PagedResultDto<T> pagedResultDto = new PagedResultDto<T>
            {
                TotalCount = count,
                Items = entityDtos
            };
            return pagedResultDto;
        }

        public static IQueryable<T> PageBy<T>(this IQueryable<T> query, IPagedResultRequest pagedResultRequest)
        {
            return query.PageBy(pagedResultRequest.SkipCount, pagedResultRequest.MaxResultCount);
        }

        public static IQueryable<T> PageBy<T>(this IQueryable<T> query, int skipCount, int maxResultCount)
        {
            if (query == null)
            {
                throw new ArgumentNullException("query");
            }

            return query.Skip(skipCount).Take(maxResultCount);
        }

        public static IQueryable<T> WhereIf<T>(this IQueryable<T> query, bool condition, Expression<Func<T, bool>> predicate)
        {
            return condition ? query.Where(predicate) : query;
        }

        public static IQueryable<T> OrderByIf<T>(this IQueryable<T> query, bool condition, string ordering)
        {
            return condition ? query.OrderBy(ordering) : query;
        }
    }
}
